/**
* @file venc.cpp
*
* Copyright (C) Huawei Technologies Co., Ltd. 2019-2020. All Rights Reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#include "acl/ops/acl_dvpp.h"
#include "common/log_inner.h"
#include "toolchain/profiling_manager.h"
#include "toolchain/resource_statistics.h"
#include "single_op/dvpp/mgr/dvpp_manager.h"

#ifdef __cplusplus
extern "C" {
#endif

aclError aclvencCreateChannel(aclvencChannelDesc *channelDesc)
{
    ACL_PROFILING_REG(acl::AclProfType::AclvencCreateChannel);
    ACL_STAGES_REG(acl::ACL_STAGE_CREATE, acl::ACL_STAGE_DEFAULT);
    ACL_ADD_APPLY_TOTAL_COUNT(acl::ACL_STATISTICS_CREATE_DESTROY_VENC_CHANNEL);
    const auto videoProcessor = acl::dvpp::DvppManager::GetInstance().GetVideoProcessor();
    if (videoProcessor == nullptr) {
        ACL_LOG_ERROR("[Check][VideoProcessor]video processor is null.");
        const char_t *argList[] = {"param"};
        const char_t *argVal[] = {"videoProcessor"};
        acl::AclErrorLogManager::ReportInputErrorWithChar(acl::INVALID_NULL_POINTER_MSG,
            argList, argVal, 1U);
        return ACL_ERROR_INTERNAL_ERROR;
    }
    const aclError aclRet = videoProcessor->aclvencCreateChannel(channelDesc);
    if (aclRet == ACL_SUCCESS) {
        ACL_ADD_APPLY_SUCCESS_COUNT(acl::ACL_STATISTICS_CREATE_DESTROY_VENC_CHANNEL);
    }
    return aclRet;
}

aclError aclvencDestroyChannel(aclvencChannelDesc *channelDesc)
{
    ACL_PROFILING_REG(acl::AclProfType::AclvencDestroyChannel);
    ACL_STAGES_REG(acl::ACL_STAGE_DESTROY, acl::ACL_STAGE_DEFAULT);
    ACL_ADD_RELEASE_TOTAL_COUNT(acl::ACL_STATISTICS_CREATE_DESTROY_VENC_CHANNEL);
    const auto videoProcessor = acl::dvpp::DvppManager::GetInstance().GetVideoProcessor();
    if (videoProcessor == nullptr) {
        ACL_LOG_ERROR("[Check][VideoProcessor]video processor is null.");
        const char_t *argList[] = {"param"};
        const char_t *argVal[] = {"videoProcessor"};
        acl::AclErrorLogManager::ReportInputErrorWithChar(acl::INVALID_NULL_POINTER_MSG,
            argList, argVal, 1U);
        return ACL_ERROR_INTERNAL_ERROR;
    }
    const aclError aclRet = videoProcessor->aclvencDestroyChannel(channelDesc);
    if (aclRet == ACL_SUCCESS) {
        ACL_ADD_RELEASE_SUCCESS_COUNT(acl::ACL_STATISTICS_CREATE_DESTROY_VENC_CHANNEL);
    }
    return aclRet;
}

aclError aclvencSendFrame(aclvencChannelDesc *channelDesc, acldvppPicDesc *input, void *reserve,
    aclvencFrameConfig *config, void *userdata)
{
    ACL_PROFILING_REG(acl::AclProfType::AclvencSendFrame);
    ACL_STAGES_REG(acl::ACL_STAGE_DVPP, acl::ACL_STAGE_DEFAULT);
    const auto videoProcessor = acl::dvpp::DvppManager::GetInstance().GetVideoProcessor();
    if (videoProcessor == nullptr) {
        ACL_LOG_ERROR("[Check][VideoProcessor]video processor is null.");
        const char_t *argList[] = {"param"};
        const char_t *argVal[] = {"videoProcessor"};
        acl::AclErrorLogManager::ReportInputErrorWithChar(acl::INVALID_NULL_POINTER_MSG,
            argList, argVal, 1U);
        return ACL_ERROR_INTERNAL_ERROR;
    }
    return videoProcessor->aclvencSendFrame(channelDesc, input, reserve, config, userdata);
}

aclError aclvencSetChannelDescThreadId(aclvencChannelDesc *channelDesc, uint64_t threadId)
{
    if (channelDesc == nullptr) {
        ACL_LOG_ERROR("channelDesc is null.");
        return ACL_ERROR_INVALID_PARAM;
    }

    channelDesc->threadId = threadId;
    return ACL_SUCCESS;
}

aclError aclvencSetChannelDescCallback(aclvencChannelDesc *channelDesc, aclvencCallback callback)
{
    if (channelDesc == nullptr) {
        ACL_LOG_INNER_ERROR("[Check][channelDesc]channelDesc is null.");
        return ACL_ERROR_INVALID_PARAM;
    }

    if (callback == nullptr) {
        ACL_LOG_INNER_ERROR("[Check][Callback]callback is null.");
        return ACL_ERROR_INVALID_PARAM;
    }

    channelDesc->callback = callback;
    return ACL_SUCCESS;
}

aclError aclvencSetChannelDescEnType(aclvencChannelDesc *channelDesc, acldvppStreamFormat enType)
{
    if (channelDesc == nullptr) {
        ACL_LOG_INNER_ERROR("[Check][channelDesc]channelDesc is null.");
        return ACL_ERROR_INVALID_PARAM;
    }

    channelDesc->vencDesc.enType = static_cast<uint32_t>(enType);
    return ACL_SUCCESS;
}

aclError aclvencSetChannelDescPicFormat(aclvencChannelDesc *channelDesc, acldvppPixelFormat picFormat)
{
    const auto videoProcessor = acl::dvpp::DvppManager::GetInstance().GetVideoProcessor();
    ACL_REQUIRES_TRUE((videoProcessor != nullptr), ACL_ERROR_INTERNAL_ERROR, "videoProcessor can not be null");
    return videoProcessor->aclvencSetChannelDescPicFormat(channelDesc, picFormat);
}

aclError aclvencSetChannelDescPicWidth(aclvencChannelDesc *channelDesc, uint32_t picWidth)
{
    if (channelDesc == nullptr) {
        ACL_LOG_INNER_ERROR("[Check][channelDesc]channelDesc is null.");
        return ACL_ERROR_INVALID_PARAM;
    }

    channelDesc->vencDesc.picWidth = picWidth;
    return ACL_SUCCESS;
}

aclError aclvencSetChannelDescPicHeight(aclvencChannelDesc *channelDesc, uint32_t picHeight)
{
    if (channelDesc == nullptr) {
        ACL_LOG_INNER_ERROR("[Check][channelDesc]channelDesc is null.");
        return ACL_ERROR_INVALID_PARAM;
    }

    channelDesc->vencDesc.picHeight = picHeight;
    return ACL_SUCCESS;
}

aclError aclvencSetChannelDescKeyFrameInterval(aclvencChannelDesc *channelDesc, uint32_t keyFrameInterval)
{
    if (channelDesc == nullptr) {
        ACL_LOG_INNER_ERROR("[Check][channelDesc]channelDesc is null.");
        return ACL_ERROR_INVALID_PARAM;
    }

    channelDesc->vencDesc.keyFrameInterval = keyFrameInterval;
    return ACL_SUCCESS;
}

aclError aclvencSetChannelDescBufAddr(aclvencChannelDesc *channelDesc, void *bufAddr)
{
    const auto videoProcessor = acl::dvpp::DvppManager::GetInstance().GetVideoProcessor();
    ACL_REQUIRES_TRUE((videoProcessor != nullptr), ACL_ERROR_INTERNAL_ERROR, "videoProcessor can not be null");
    return videoProcessor->aclvencSetChannelDescBufAddr(channelDesc, bufAddr);
}

aclError aclvencSetChannelDescRcMode(aclvencChannelDesc *channelDesc, uint32_t rcMode)
{
    const auto videoProcessor = acl::dvpp::DvppManager::GetInstance().GetVideoProcessor();
    ACL_REQUIRES_TRUE((videoProcessor != nullptr), ACL_ERROR_INTERNAL_ERROR, "videoProcessor can not be null");
    return videoProcessor->aclvencSetChannelDescRcMode(channelDesc, rcMode);
}

aclError aclvencSetChannelDescSrcRate(aclvencChannelDesc *channelDesc, uint32_t srcRate)
{
    const auto videoProcessor = acl::dvpp::DvppManager::GetInstance().GetVideoProcessor();
    ACL_REQUIRES_TRUE((videoProcessor != nullptr), ACL_ERROR_INTERNAL_ERROR, "videoProcessor can not be null");
    return videoProcessor->aclvencSetChannelDescSrcRate(channelDesc, srcRate);
}

aclError aclvencSetChannelDescMaxBitRate(aclvencChannelDesc *channelDesc, uint32_t maxBitRate)
{
    const auto videoProcessor = acl::dvpp::DvppManager::GetInstance().GetVideoProcessor();
    ACL_REQUIRES_TRUE((videoProcessor != nullptr), ACL_ERROR_INTERNAL_ERROR, "videoProcessor can not be null");
    return videoProcessor->aclvencSetChannelDescMaxBitRate(channelDesc, maxBitRate);
}

aclError aclvencSetChannelDescBufSize(aclvencChannelDesc *channelDesc, uint32_t bufSize)
{
    const auto videoProcessor = acl::dvpp::DvppManager::GetInstance().GetVideoProcessor();
    ACL_REQUIRES_TRUE((videoProcessor != nullptr), ACL_ERROR_INTERNAL_ERROR, "videoProcessor can not be null");
    return videoProcessor->aclvencSetChannelDescBufSize(channelDesc, bufSize);
}

aclError aclvencSetFrameConfigForceIFrame(aclvencFrameConfig *config, uint8_t forceIFrame)
{
    ACL_LOG_DEBUG("start to execute aclvencSetFrameConfigForceIFrame");
    ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(config);
    config->vencFrameConfig.forceIFrame = (forceIFrame != 0U);
    return ACL_SUCCESS;
}

aclError aclvencSetFrameConfigEos(aclvencFrameConfig *config, uint8_t eos)
{
    ACL_LOG_DEBUG("start to execute aclvencSetFrameConfigEos");
    ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(config);
    config->vencFrameConfig.eos = (eos == 0U) ? false : true;
    return ACL_SUCCESS;
}

uint32_t aclvencGetChannelDescBufSize(const aclvencChannelDesc *channelDesc)
{
    const auto videoProcessor = acl::dvpp::DvppManager::GetInstance().GetVideoProcessor();
    if (videoProcessor == nullptr) {
        ACL_LOG_INNER_ERROR("[Check][videoProcessor]channelDesc is null");
        return 0U;
    }
    bool isSupport = false;
    return videoProcessor->aclvencGetChannelDescBufSize(channelDesc, isSupport);
}

void *aclvencGetChannelDescBufAddr(const aclvencChannelDesc *channelDesc)
{
    const auto videoProcessor = acl::dvpp::DvppManager::GetInstance().GetVideoProcessor();
    ACL_REQUIRES_NOT_NULL_RET_NULL(videoProcessor);
    bool isSupport = false;
    return videoProcessor->aclvencGetChannelDescBufAddr(channelDesc, isSupport);
}

uint32_t aclvencGetChannelDescChannelId(const aclvencChannelDesc *channelDesc)
{
    if (channelDesc == nullptr) {
        ACL_LOG_INNER_ERROR("[Check][ChannelDesc]channelDesc is null");
        return 0U; // default 0
    }
    return channelDesc->vencDesc.channelId;
}

uint64_t aclvencGetChannelDescThreadId(const aclvencChannelDesc *channelDesc)
{
    if (channelDesc == nullptr) {
        ACL_LOG_INNER_ERROR("[Check][ChannelDesc]channelDesc is null");
        return 0U; // default 0
    }
    return channelDesc->threadId;
}

aclvencCallback aclvencGetChannelDescCallback(const aclvencChannelDesc *channelDesc)
{
    if (channelDesc == nullptr) {
        ACL_LOG_INNER_ERROR("[Check][ChannelDesc]channelDesc or callback is null.");
        return nullptr; // default null
    }
    return channelDesc->callback;
}

acldvppStreamFormat aclvencGetChannelDescEnType(const aclvencChannelDesc *channelDesc)
{
    if (channelDesc == nullptr) {
        ACL_LOG_INNER_ERROR("[Check][ChannelDesc]channelDesc is null.");
        return H265_MAIN_LEVEL; // default H265_MAIN_LEVEL
    }
    return static_cast<acldvppStreamFormat>(channelDesc->vencDesc.enType);
}

acldvppPixelFormat aclvencGetChannelDescPicFormat(const aclvencChannelDesc *channelDesc)
{
    if (channelDesc == nullptr) {
        ACL_LOG_INNER_ERROR("[Check][ChannelDesc]channelDesc is null.");
        return PIXEL_FORMAT_YUV_SEMIPLANAR_420; // default PIXEL_FORMAT_YUV_SEMIPLANAR_420
    }
    return static_cast<acldvppPixelFormat>(channelDesc->vencDesc.picFormat);
}

uint32_t aclvencGetChannelDescPicWidth(const aclvencChannelDesc *channelDesc)
{
    if (channelDesc == nullptr) {
        ACL_LOG_INNER_ERROR("[Check][ChannelDesc]channelDesc is null.");
        return 0U; // default 0
    }
    return channelDesc->vencDesc.picWidth;
}

uint32_t aclvencGetChannelDescPicHeight(const aclvencChannelDesc *channelDesc)
{
    if (channelDesc == nullptr) {
        ACL_LOG_INNER_ERROR("[Check][ChannelDesc]channelDesc is null.");
        return 0U; // default 0
    }
    return channelDesc->vencDesc.picHeight;
}

uint32_t aclvencGetChannelDescKeyFrameInterval(const aclvencChannelDesc *channelDesc)
{
    if (channelDesc == nullptr) {
        ACL_LOG_INNER_ERROR("[Check][ChannelDesc]channelDesc is null.");
        return 0U; // default 0
    }
    return channelDesc->vencDesc.keyFrameInterval;
}

uint32_t aclvencGetChannelDescRcMode(const aclvencChannelDesc *channelDesc)
{
    const auto videoProcessor = acl::dvpp::DvppManager::GetInstance().GetVideoProcessor();
    if (videoProcessor == nullptr) {
        ACL_LOG_INNER_ERROR("[Check][VideoProcessor]video processor is null.");
        return 0U;
    }
    bool isSupport = false;
    return videoProcessor->aclvencGetChannelDescRcMode(channelDesc, isSupport);
}

uint32_t aclvencGetChannelDescSrcRate(const aclvencChannelDesc *channelDesc)
{
    const auto videoProcessor = acl::dvpp::DvppManager::GetInstance().GetVideoProcessor();
    if (videoProcessor == nullptr) {
        ACL_LOG_INNER_ERROR("[Check][VideoProcessor]video processor is null.");
        return 0U;
    }
    bool isSupport = false;
    return videoProcessor->aclvencGetChannelDescSrcRate(channelDesc, isSupport);
}

uint32_t aclvencGetChannelDescMaxBitRate(const aclvencChannelDesc *channelDesc)
{
    const auto videoProcessor = acl::dvpp::DvppManager::GetInstance().GetVideoProcessor();
    if (videoProcessor == nullptr) {
        ACL_LOG_INNER_ERROR("[Check][VideoProcessor]video processor is null.");
        return 0U;
    }
    bool isSupport = false;
    return videoProcessor->aclvencGetChannelDescMaxBitRate(channelDesc, isSupport);
}

uint8_t aclvencGetFrameConfigForceIFrame(const aclvencFrameConfig *config)
{
    ACL_LOG_DEBUG("start to execute aclvencGetFrameConfigForceIFrame");
    if (config == nullptr) {
        ACL_LOG_ERROR("[Check][Config]config is null");
        const char_t *argList[] = {"param"};
        const char_t *argVal[] = {"config"};
        acl::AclErrorLogManager::ReportInputErrorWithChar(acl::INVALID_NULL_POINTER_MSG,
                                                          argList, argVal, 1U);
        return 0U; // default 0
    }
    return static_cast<uint8_t>(config->vencFrameConfig.forceIFrame);
}

uint8_t aclvencGetFrameConfigEos(const aclvencFrameConfig *config)
{
    ACL_LOG_DEBUG("start to execute aclvencGetFrameConfigEos");
    if (config == nullptr) {
        ACL_LOG_ERROR("config is null");
        return 0U; // default 0
    }
    return static_cast<uint8_t>(config->vencFrameConfig.eos);
}

#ifdef __cplusplus
}
#endif
